package com.test.socket.clientSocket
{
	import com.utils.LoaclTime;
	import com.utils.ObjectTranslator;
	
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.events.TimerEvent;
	import flash.net.Socket;
	import flash.utils.ByteArray;
	import flash.utils.Timer;
	import com.test.socket.messages.Message;
	import com.test.socket.model.Constant;
	
	public class ClientSocketManager extends Sprite
	{
		public static const instance:ClientSocketManager = new ClientSocketManager;
		private static var _stopAcceptUserList:Vector.<String> = new Vector.<String>();
		private const MAX_LINK_COUNT:int = 10;
		private var _restartLinkDealy:Number = 100;
		private var _curLinkCount:int = 0;
		private var _timer:Timer;
		
		private var _socket:Socket;
		private var _host:String;
		private var _port:int;
		
		private var _userName:String = '';
		private var _userList:Array = [];

		private var _appendText:Function = new Function();
		private var _showAlertTip:Function = new Function();
		
		public function ClientSocketManager()
		{
			if(instance) throw Error('不能重复实例化！')
		}
		
		/**
		 * 创建Socket连接
		 * @param host 主机地址
		 * @param port 端口号
		 */		
		public function createSocket(host:String,port:int,userName:String = ''):void
		{
			if(_socket) return;
			_host = host;
			_port = port;
			_userName = userName;
			_socket = new Socket();
			_socket.addEventListener(Event.CONNECT,onConnetHandler);
			_socket.addEventListener(ProgressEvent.SOCKET_DATA,onProgressHandler);
			_socket.addEventListener(Event.CLOSE,onCloseHandler);
			_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityErrorHandler);
			_socket.addEventListener(IOErrorEvent.IO_ERROR,onIOErrorHandler);
			_appendText('开始连接服务器...')
			startLinkServer();
		}
		
		/**连接服务器*/		
		private function linkServer():void{
			_socket.connect(_host,_port);
		}
		
		private function onIOErrorHandler(e:IOErrorEvent):void
		{
			trace('IOErrorEvent：' +e.text)
		}
		
		private function onSecurityErrorHandler(e:SecurityErrorEvent):void
		{
			trace('SecurityErrorEvent:' + e.text);
		}
		
		/**服务器关闭*/		
		private function onCloseHandler(e:Event):void
		{
			_showAlertTip('服务器已断开链接!')
			//closeLinkServer();
		}
		
		/**连接成功提示*/		
		private function onConnetHandler(e:Event):void
		{
			if(!_socket.connected) return;
			_curLinkCount = 0;
			clearTimer();
			_appendText('服务器链接成功!');
			_appendText('////////////////////\n本机用户:' + _userName + '\n////////////////////');
			sendMsg(Constant.LOGIN_HEAD,'登录')
		}	
		
		/**接收服务器数据*/		
		private function onProgressHandler(e:ProgressEvent):void
		{
			var msg:Message = ObjectTranslator.objectToInstance(_socket.readObject(),Message);
			checkMessageType(msg);
		}
		
		/**不同类型执行不同动作*/		
		private function checkMessageType(msg:Message):void
		{
			switch(msg.type)
			{
				case Constant.LOGIN_HEAD://用户登录
					_appendText(msg.userName + msg.body);
					break;
				case Constant.MESSAGE_HEAD://普通消息
					if(!userMsgAcceptState(msg.userName)){
						trace(msg.userName+'消息被屏蔽!')
						return;
					}
					_appendText(msg.body,msg.userName + LoaclTime.timeDateFormat(false));
					break;
				case Constant.LOGIN_OUT_HEAD://客户端离开消
					_appendText(msg.userName + msg.body);
					break;
				case Constant.USER_LIST://用户列表消息
					_userList = msg.body.split('\n');
					_appendText('在线用户:\n' + msg.body,'',1);
					break;
				case Constant.SHIELD_HEAD://屏蔽用户
					//没有屏蔽操作
					_appendText(msg.userName + msg.body);
					break;
				case Constant.SERVER_BROADCAST://广播
					_appendText(msg.body,msg.userName+ LoaclTime.timeDateFormat(false));
					break;
				default:
					break;
			}
		}
		
		/**向服务器发送消息*/		
		public function sendMsg(msgType:int,value:*):void
		{
			if(!_socket.connected) return;
			_socket.writeObject(dataPacket(msgType,_userName,value));
			_socket.flush();
		}
		
		/**检测用户是否在屏蔽列表中*/		
		private function userMsgAcceptState(userName:String):Boolean
		{
			for (var i:int = 0; i < _stopAcceptUserList.length; i++) 
			{
				if(userName == _stopAcceptUserList[i]){
					return false;
				}
			}
			return true;
		}
		
		/**将用户添加到屏蔽列表中*/		
		public function addStopAcceptUser(name:String):void
		{
			if(!_stopAcceptUserList) _stopAcceptUserList = new Vector.<String>();
			if(_stopAcceptUserList.indexOf(name) == -1){
				_stopAcceptUserList.push(name)
				_showAlertTip(name +'已被屏蔽！');
			}else{
				_showAlertTip('此用户一再屏蔽列表中！');
			}
		}
		
		
		/**连接服务器*/		
		private function startLinkServer():void{
			if(!_timer){
				_timer = new Timer(_restartLinkDealy);
				_timer.addEventListener(TimerEvent.TIMER,onTimerHandler);
			}
			_timer.start();
		}
		
		/**启动timer事件*/		
		private function onTimerHandler(e:TimerEvent):void
		{
			linkServer();
			if(_curLinkCount > MAX_LINK_COUNT){
				clearTimer();
				_curLinkCount = 0;
				_showAlertTip('链接超时!');
				closeLinkServer();
				return;
			}
			_curLinkCount++;
		}
		
		/**清除timer事件，停止连接*/		
		private function clearTimer():void{
			if(!_timer) return;
			_timer.stop();
			_timer.removeEventListener(TimerEvent.TIMER,onTimerHandler);
			_timer = null;
		}
		
		/**关闭连接*/		
		public function closeLinkServer():void{
			if(_socket){
				_socket.removeEventListener(Event.CONNECT,onConnetHandler);
				_socket.removeEventListener(ProgressEvent.SOCKET_DATA,onProgressHandler);
				_socket.removeEventListener(Event.CLOSE,onCloseHandler);
				_socket.removeEventListener(SecurityErrorEvent.SECURITY_ERROR,onSecurityErrorHandler);
				_socket.close();
				_socket = null;
			}
		}
		
		/**获取数据包*/		
		private function dataPacket(type:int,head:String,body:*):Message
		{
			var msg:Message = new Message();
			msg.type = type;
			msg.userName = head;
			msg.body = body;
			return msg;
		}
		
		
		
		
		
		
		
		
		
		
		public function get userList():Array{return _userList;}
		
		public function set appendText(value:Function):void{_appendText = value;}
		
		public function set showAlertTip(value:Function):void{_showAlertTip = value;}
	}
}

